/*****************************************************************************************
   
   Copyright (c) Microsoft Corporation. All rights reserved.

   Use of this code sample is subject to the terms of the Microsoft
   Permissive License, a copy of which should always be distributed with
   this file.  You can also access a copy of this license agreement at:
   http://www.microsoft.com/resources/sharedsource/licensingbasics/permissivelicense.mspx

 ****************************************************************************************/

using System;

namespace GrooveWebServicesV12Helpers.Calendar
{
	/// <summary>
	/// Represents a Calendar tool in a Groove workspace.
	/// </summary>
	public class CalendarTool : 
		GrooveWebServicesV12Helpers.Tool,
		GrooveWebServicesV12Helpers.Shared.IGrooveWebServicesEventCallback
	{
		internal static System.Collections.SortedList s_CalendarToolEventManagerSortedList = new System.Collections.SortedList();
		private int m_CalendarToolEventManagerCount = 0;

		private string m_CalendarSubscriptionID;

		private GrooveCalendarWebService.GrooveCalendar m_GrooveCalendar;

		public CalendarTool(GrooveWebServicesV12Helpers.Space i_Space, GrooveToolsWebService.Tool i_Tool) :
			base(i_Space, i_Tool)
		{
			//  Make sure we are dealing with a 2.5 or later Calendar tool
			if (this.Type != GrooveWebServicesV12Helpers.Shared.GROOVE_CALENDAR_TOOL_SUPPORTED_TYPE)
				throw new System.ArgumentException("Tool is not a Groove 2.5 or later Calendar tool!");
		}

		#region Calendar Properties And Methods

		public static System.Data.DataSet CreateDataSetFromCalendarEntries(GrooveWebServicesV12Helpers.GrooveCalendarWebService.CalendarEntry[] i_CalendarEntries)
		{
			System.Data.DataSet DataSet = new System.Data.DataSet("Data");
			System.Data.DataTable DataTable = int_CreateDataTable();

			foreach (GrooveWebServicesV12Helpers.GrooveCalendarWebService.CalendarEntry CalendarEntry in i_CalendarEntries)
			{
				System.Data.DataRow DataRow = DataTable.NewRow();
							
				DataRow["ID"] = CalendarEntry.ID;
				DataRow["URI"] = CalendarEntry.URI;
				DataRow["CreatedBy"] = CalendarEntry.CreatedBy;
				DataRow["ModifiedBy"] = CalendarEntry.ModifiedBy;
				DataRow["Created"] = CalendarEntry.Created;
				DataRow["Modified"] = CalendarEntry.Modified;
				DataRow["Unread"] = CalendarEntry.Unread;
				DataRow["Description"] = CalendarEntry.Description;
				DataRow["Category"] = CalendarEntry.Category;
				DataRow["Details"] = CalendarEntry.Details;
				DataRow["Start"] = CalendarEntry.Start;
				DataRow["End"] = CalendarEntry.End;
				DataRow["AllDay"] = CalendarEntry.AllDay;

				DataTable.Rows.Add(DataRow);
			}
			
			DataSet.Tables.Add(DataTable);
			DataSet.AcceptChanges();

			return DataSet;
		}

		public static System.Data.DataSet CreateDataSetFromCalendarEntries(GrooveWebServicesV12Helpers.Calendar.CalendarEntry[] i_CalendarEntries)
		{
			System.Data.DataSet DataSet = new System.Data.DataSet("Data");
			System.Data.DataTable DataTable = int_CreateDataTable();

			foreach (GrooveWebServicesV12Helpers.Calendar.CalendarEntry CalendarEntry in i_CalendarEntries)
			{
				System.Data.DataRow DataRow = DataTable.NewRow();
							
				DataRow["ID"] = CalendarEntry.ID;
				DataRow["URI"] = CalendarEntry.URI;
				DataRow["CreatedBy"] = CalendarEntry.CreatedBy;
				DataRow["ModifiedBy"] = CalendarEntry.ModifiedBy;
				DataRow["Created"] = CalendarEntry.Created;
				DataRow["Modified"] = CalendarEntry.Modified;
				DataRow["Unread"] = CalendarEntry.Unread;
				DataRow["Description"] = CalendarEntry.Description;
				DataRow["Category"] = CalendarEntry.Category;
				DataRow["Details"] = CalendarEntry.Details;
				DataRow["Start"] = CalendarEntry.Start;
				DataRow["End"] = CalendarEntry.End;
				DataRow["AllDay"] = CalendarEntry.AllDay;

				DataTable.Rows.Add(DataRow);
			}
			
			DataSet.Tables.Add(DataTable);
			DataSet.AcceptChanges();

			return DataSet;
		}

		private static System.Data.DataTable int_CreateDataTable()
		{
			System.Data.DataTable DataTable = new System.Data.DataTable("CalendarData");
			
			DataTable.Columns.Add("ID", typeof(string));
			DataTable.Columns.Add("URI", typeof(string));
			DataTable.Columns.Add("CreatedBy", typeof(string));
			DataTable.Columns.Add("ModifiedBy", typeof(string));
			DataTable.Columns.Add("Created", typeof(System.DateTime));
			DataTable.Columns.Add("Modified", typeof(System.DateTime));
			DataTable.Columns.Add("Unread", typeof(bool));
			DataTable.Columns.Add("Description", typeof(string));
			DataTable.Columns.Add("Category", typeof(string));
			DataTable.Columns.Add("Details", typeof(string));
			DataTable.Columns.Add("Start", typeof(System.DateTime));
			DataTable.Columns.Add("End", typeof(System.DateTime));
			DataTable.Columns.Add("AllDay", typeof(bool));

			return DataTable;
		}

		public static GrooveCalendarWebService.GrooveCalendar CreateInitializedCalendarWebService(string i_IdentityURL, string i_TargetURI, GrooveWebServicesV12Helpers.Context i_Context)
		{
			//  Create the service
			GrooveCalendarWebService.GrooveCalendar CalendarWebService = new GrooveCalendarWebService.GrooveCalendar();

			//  Create the Groove SOAP header
			CalendarWebService.GrooveRequestHeaderValue = new GrooveCalendarWebService.GrooveRequestHeader();

			//  Set appropriate header values
			CalendarWebService.GrooveRequestHeaderValue.GrooveRequestKey = i_Context.RequestKey;
			CalendarWebService.GrooveRequestHeaderValue.GrooveIdentityURL = i_IdentityURL;

			//  Set the URL
			CalendarWebService.Url = i_Context.Host + i_TargetURI;

			//  Set Timeout
			CalendarWebService.Timeout = i_Context.Timeout;

			return CalendarWebService;
		}

		public GrooveWebServicesV12Helpers.Calendar.CalendarEntry[] CalendarEntries
		{
			get
			{
				//  Get initialized reference to web service
				GrooveCalendarWebService.GrooveCalendar CalendarWebService = this.GetInitializedCalendarWebService(this.Data);

				System.DateTime BeginDateTime = System.DateTime.Now;

				//  Ask service to provide the list of calendar entries for this tool
				GrooveCalendarWebService.CalendarEntry[] CalendarEntries = CalendarWebService.Read();

				if (GrooveWebServicesV12Helpers.Context.TraceEnabled)
				{
					System.TimeSpan TimeSpan = System.DateTime.Now.Subtract(BeginDateTime);
					System.Diagnostics.Debug.WriteLine("CalendarWebService::Read, " + TimeSpan.TotalMilliseconds + " ms");
				}

				//  Create array list of calendar entries
				System.Collections.ArrayList CalendarEntryArrayList = new System.Collections.ArrayList();
				foreach (GrooveCalendarWebService.CalendarEntry CalendarEntry in CalendarEntries)
				{
					GrooveWebServicesV12Helpers.Calendar.CalendarEntry NewCalendarEntry = new GrooveWebServicesV12Helpers.Calendar.CalendarEntry
						(
						this,
						CalendarEntry
						);

					CalendarEntryArrayList.Add(NewCalendarEntry);
				}

				//  Return array from array list
				return (GrooveWebServicesV12Helpers.Calendar.CalendarEntry[])CalendarEntryArrayList.ToArray(typeof(GrooveWebServicesV12Helpers.Calendar.CalendarEntry));
			}
		}

		/// <summary>
		/// Find calendar entries matching a keyword in their Description or Details
		/// </summary>
		/// <param name="i_Keyword">Partial text (case insensitive)</param>
		/// <returns>Array of CalendarEntry</returns>
		public GrooveWebServicesV12Helpers.Calendar.CalendarEntry[] FindMatchingEntries(string i_Keyword)
		{
			//  Check for valid keyword
			if (i_Keyword.Length == 0)
				throw new System.ArgumentException("No keyword specified!");

			string NormalizedKeyword = i_Keyword.ToLower();

			//  Get list of calendar entries for this tool
			GrooveWebServicesV12Helpers.Calendar.CalendarEntry[] CalendarEntries = this.CalendarEntries;

			System.Collections.ArrayList CalendarEntryArrayList = new System.Collections.ArrayList();

			//  Only do work if calendar entries exist
			if (CalendarEntries.Length > 0)
			{
				//  Iterate through file descriptors
				foreach (GrooveWebServicesV12Helpers.Calendar.CalendarEntry CalendarEntry in CalendarEntries)
				{
					string NormalizedDescription = CalendarEntry.Description.ToLower();
					string NormalizedDetails = CalendarEntry.Details.ToLower();

					bool FoundMatch = 
						(NormalizedDescription.IndexOf(NormalizedKeyword) >= 0) ||
						(NormalizedDetails.IndexOf(NormalizedKeyword) >= 0);

					if (FoundMatch)
						CalendarEntryArrayList.Add(CalendarEntry);
				}
			}

			//  Create array list of calendar entries
			foreach (GrooveCalendarWebService.CalendarEntry CalendarEntry in CalendarEntryArrayList)
			{
				GrooveWebServicesV12Helpers.Calendar.CalendarEntry NewCalendarEntry = new GrooveWebServicesV12Helpers.Calendar.CalendarEntry
					(
					this,
					CalendarEntry
					);

				CalendarEntryArrayList.Add(NewCalendarEntry);
			}

			//  Return array from array list
			return (GrooveWebServicesV12Helpers.Calendar.CalendarEntry[])CalendarEntryArrayList.ToArray(typeof(GrooveWebServicesV12Helpers.Calendar.CalendarEntry));
		}

		public string AddEntry(string i_Category, string i_Description, string i_Details, bool i_AllDay, System.DateTime i_Start, System.DateTime i_End)
		{
			//  Get initialized reference to web service
			GrooveCalendarWebService.GrooveCalendar CalendarWebService = this.GetInitializedCalendarWebService(this.Data);

			//  Set parameters
			GrooveCalendarWebService.CalendarEntry CalendarEntry = new GrooveCalendarWebService.CalendarEntry();
			CalendarEntry.AllDay = i_AllDay;
			CalendarEntry.Category = i_Category;
			CalendarEntry.Description = i_Description;
			CalendarEntry.Details = i_Details;
			CalendarEntry.Start = i_Start;
			CalendarEntry.End = i_End;

			System.DateTime BeginDateTime = System.DateTime.Now;

			//  Ask service to create calendar entry
			string CalendarEntryURI = CalendarWebService.Create(CalendarEntry);

			if (GrooveWebServicesV12Helpers.Context.TraceEnabled)
			{
				System.TimeSpan TimeSpan = System.DateTime.Now.Subtract(BeginDateTime);
				System.Diagnostics.Debug.WriteLine("CalendarWebService::Create, " + TimeSpan.TotalMilliseconds + " ms");
			}

			return CalendarEntryURI;
		}

		public GrooveWebServicesV12Helpers.Calendar.CalendarEntry OpenEntry(string i_CalendarEntryURI)
		{
			//  Get initialized reference to web service
			GrooveCalendarWebService.GrooveCalendar CalendarWebService = this.GetInitializedCalendarWebService(i_CalendarEntryURI);

			System.DateTime BeginDateTime = System.DateTime.Now;

			//  Ask service to read calendar entry
			GrooveCalendarWebService.CalendarEntry ExistingCalendarEntry = CalendarWebService.ReadEntry();

			if (GrooveWebServicesV12Helpers.Context.TraceEnabled)
			{
				System.TimeSpan TimeSpan = System.DateTime.Now.Subtract(BeginDateTime);
				System.Diagnostics.Debug.WriteLine("CalendarWebService::ReadEntry, " + TimeSpan.TotalMilliseconds + " ms");
			}

			//  Create helper class
			GrooveWebServicesV12Helpers.Calendar.CalendarEntry CalendarEntry = new GrooveWebServicesV12Helpers.Calendar.CalendarEntry
				(
				this,
				ExistingCalendarEntry
				);

			return CalendarEntry;
		}

		public void RemoveEntry(string i_CalendarEntryURI)
		{
			//  Get initialized reference to web service
			GrooveCalendarWebService.GrooveCalendar CalendarWebService = this.GetInitializedCalendarWebService(i_CalendarEntryURI);

			System.DateTime BeginDateTime = System.DateTime.Now;

			//  Ask service to delete calendar entry
			CalendarWebService.DeleteEntry();

			if (GrooveWebServicesV12Helpers.Context.TraceEnabled)
			{
				System.TimeSpan TimeSpan = System.DateTime.Now.Subtract(BeginDateTime);
				System.Diagnostics.Debug.WriteLine("CalendarWebService::DeleteEntry, " + TimeSpan.TotalMilliseconds + " ms");
			}
		}

		private GrooveCalendarWebService.GrooveCalendar GetInitializedCalendarWebService(string i_TargetURI)
		{
            if ((m_GrooveCalendar == null) || Context.ReinitNeeded(m_GrooveCalendar.GrooveRequestHeaderValue.GrooveRequestKey))
			{
				m_GrooveCalendar = GrooveWebServicesV12Helpers.Calendar.CalendarTool.CreateInitializedCalendarWebService
					(
					m_IdentityURL,
					i_TargetURI,
					Context
					);
			}
			else
			{
				//  Explicitly overwrite target URL and Timeout
				m_GrooveCalendar.Url = Context.Host + i_TargetURI;
                m_GrooveCalendar.Timeout = Context.Timeout;
			}

			return m_GrooveCalendar;
		}

		#endregion

		#region Calendar Event Handling

		private void IncrementCalendarToolSubscriptionCount()
		{
			lock (s_CalendarToolEventManagerSortedList)
			{
				if (m_CalendarToolEventManagerCount == 0)
				{
					m_CalendarSubscriptionID = GrooveWebServicesV12Helpers.EventManager.AddEventListener
						(
						Context,
						this.IdentityURL,
						GrooveWebServicesV12Helpers.Shared.GROOVE_WEB_SERVICES_CALENDAR_EVENT_CLASS, 
						this.Data,
						GrooveWebServicesV12Helpers.EventManager.s_EventURI,
						this
						);
				}

				++m_CalendarToolEventManagerCount;
			}
		}

		private void DecrementCalendarToolSubscriptionCount()
		{
			lock (s_CalendarToolEventManagerSortedList)
			{
				--m_CalendarToolEventManagerCount;

				if (m_CalendarToolEventManagerCount == 0)
				{
					GrooveWebServicesV12Helpers.EventManager.RemoveEventListener
						(
						m_CalendarSubscriptionID,
						this
						);

					m_CalendarSubscriptionID = null;
				}
			}
		}

		internal void RaiseCalendarEntriesAddedEvent(GrooveCalendarWebService.CalendarEntry[] i_CalendarEntries)
		{
			//  If one or more subscribers, broadcast event
			if (InternalOnCalendarEntriesAddedEvent != null)
			{
				//  Create array list of calendar entries
				System.Collections.ArrayList CalendarEntryArrayList = new System.Collections.ArrayList();

				foreach (GrooveCalendarWebService.CalendarEntry CalendarEntry in i_CalendarEntries)
				{
					GrooveWebServicesV12Helpers.Calendar.CalendarEntry NewCalendarEntry = new GrooveWebServicesV12Helpers.Calendar.CalendarEntry
						(
						this,
						CalendarEntry
						);

					CalendarEntryArrayList.Add(NewCalendarEntry);
				}

				//  Convert array list to array
				GrooveWebServicesV12Helpers.Calendar.CalendarEntry[] CalendarEntries = (GrooveWebServicesV12Helpers.Calendar.CalendarEntry[])CalendarEntryArrayList.ToArray(typeof(GrooveWebServicesV12Helpers.Calendar.CalendarEntry));

				InternalOnCalendarEntriesAddedEvent(CalendarEntries);
			}
		}

		internal void RaiseCalendarEntriesRemovedEvent(string[] i_CalendarIDs)
		{
			//  If one or more subscribers, broadcast event
			if (InternalOnCalendarEntriesRemovedEvent != null)
			{
				//  Create array list of calendar ids
				System.Collections.ArrayList CalendarEntryURIArrayList = new System.Collections.ArrayList();
				
				string ToolURI = this.URI + "/DataModelDelegate/";
				ToolURI = ToolURI.Replace("Tools", "Calendar");

				foreach (string CalendarID in i_CalendarIDs)
				{
					string CalendarEntryURI = ToolURI + CalendarID;
					CalendarEntryURIArrayList.Add(CalendarEntryURI);
				}

				InternalOnCalendarEntriesRemovedEvent((string[])CalendarEntryURIArrayList.ToArray(typeof(string)));
			}
		}

		internal void RaiseCalendarEntriesUpdatedEvent(GrooveCalendarWebService.CalendarEntry[] i_CalendarEntries)
		{
			//  If one or more subscribers, broadcast event
			if (InternalOnCalendarEntriesUpdatedEvent != null)
			{
				//  Create array list of calendar entries
				System.Collections.ArrayList CalendarEntryArrayList = new System.Collections.ArrayList();

				foreach (GrooveCalendarWebService.CalendarEntry CalendarEntry in i_CalendarEntries)
				{
					GrooveWebServicesV12Helpers.Calendar.CalendarEntry NewCalendarEntry = new GrooveWebServicesV12Helpers.Calendar.CalendarEntry
						(
						this,
						CalendarEntry
						);

					CalendarEntryArrayList.Add(NewCalendarEntry);
				}

				//  Convert array list to array
				GrooveWebServicesV12Helpers.Calendar.CalendarEntry[] CalendarEntries = (GrooveWebServicesV12Helpers.Calendar.CalendarEntry[])CalendarEntryArrayList.ToArray(typeof(GrooveWebServicesV12Helpers.Calendar.CalendarEntry));

				InternalOnCalendarEntriesUpdatedEvent(CalendarEntries);
			}
		}

		public delegate void OnCalendarEntriesAddedDelegate(GrooveWebServicesV12Helpers.Calendar.CalendarEntry[] i_CalendarEntries);
		internal event OnCalendarEntriesAddedDelegate InternalOnCalendarEntriesAddedEvent;
		public event OnCalendarEntriesAddedDelegate OnCalendarEntriesAddedEvent
		{
			add
			{
				IncrementCalendarToolSubscriptionCount();
				InternalOnCalendarEntriesAddedEvent += value;
			}
			remove
			{
				InternalOnCalendarEntriesAddedEvent -= value;
				DecrementCalendarToolSubscriptionCount();
			}
		}

		public delegate void OnCalendarEntriesRemovedDelegate(string[] i_CalendarIDArray);
		internal event OnCalendarEntriesRemovedDelegate InternalOnCalendarEntriesRemovedEvent;
		public event OnCalendarEntriesRemovedDelegate OnCalendarEntriesRemovedEvent
		{
			add
			{
				IncrementCalendarToolSubscriptionCount();
				InternalOnCalendarEntriesRemovedEvent += value;
			}
			remove
			{
				InternalOnCalendarEntriesRemovedEvent -= value;
				DecrementCalendarToolSubscriptionCount();
			}
		}

		public delegate void OnCalendarEntriesUpdatedDelegate(GrooveWebServicesV12Helpers.Calendar.CalendarEntry[] i_CalendarEntries);
		internal event OnCalendarEntriesUpdatedDelegate InternalOnCalendarEntriesUpdatedEvent;
		public event OnCalendarEntriesUpdatedDelegate OnCalendarEntriesUpdatedEvent
		{
			add
			{
				IncrementCalendarToolSubscriptionCount();
				InternalOnCalendarEntriesUpdatedEvent += value;
			}
			remove
			{
				InternalOnCalendarEntriesUpdatedEvent -= value;
				DecrementCalendarToolSubscriptionCount();
			}
		}

		#endregion

		#region GrooveWebServicesV12HelpersBase Implementation

		public override object BindToObject(ref string[] i_URLParts, int i_URLPartIndex)
		{
			object BindResult = null;

			string CalendarEntryURI = this.Data + "/" + i_URLParts[i_URLPartIndex];

			try
			{
				BindResult = this.OpenEntry(CalendarEntryURI);
			}
			catch (System.Exception Exception)
			{
				throw new System.Exception("Unable to find entry '" + CalendarEntryURI +"' (" + Exception.Message + ")");
			}

			return BindResult;
		}

		#endregion

		#region IGrooveWebServicesEventCallback Members

		public void ProcessEvent(GrooveEventsWebService.Event i_Event)
		{
			switch (i_Event.EventType)
			{
				case GrooveWebServicesV12Helpers.Shared.GROOVE_CALENDAR_ADD_EVENT_TYPE:
				{
					GrooveEventsWebService.GrooveCalendarAddEventData CalendarAddEventData = (GrooveEventsWebService.GrooveCalendarAddEventData)i_Event.EventData;
					this.RaiseCalendarEntriesAddedEvent(CalendarAddEventData.CalendarEntries);

					break;
				}

				case GrooveWebServicesV12Helpers.Shared.GROOVE_CALENDAR_DELETE_EVENT_TYPE:
				{
					GrooveEventsWebService.GrooveCalendarDeleteEventData CalendarDeleteEventData = (GrooveEventsWebService.GrooveCalendarDeleteEventData)i_Event.EventData;
					this.RaiseCalendarEntriesRemovedEvent(CalendarDeleteEventData.CalendarIDs);

					break;
				}

				case GrooveWebServicesV12Helpers.Shared.GROOVE_CALENDAR_UPDATE_EVENT_TYPE:
				{
					GrooveEventsWebService.GrooveCalendarUpdateEventData CalendarUpdateEventData = (GrooveEventsWebService.GrooveCalendarUpdateEventData)i_Event.EventData;
					this.RaiseCalendarEntriesUpdatedEvent(CalendarUpdateEventData.CalendarEntries);

					break;
				}

				default:
				{
					System.Diagnostics.Debug.WriteLine("[CalendarTool]Unknown event type: " + i_Event.EventType);
					break;
				}
			}
		}

		#endregion
	}
}
